package com.jingdianjichi.club.gateway.auth;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Sa-Token权限认证配置器
 * 
 * 该配置类用于配置Sa-Token在Spring Cloud Gateway中的权限认证规则，
 * 通过SaReactorFilter实现对不同路由的访问控制和权限验证。
 * 
 * 主要功能：
 * 1. 配置路由拦截规则
 * 2. 设置登录验证逻辑
 * 3. 配置权限验证规则
 * 4. 处理认证异常
 *
 * @author: ChickenWing
 * @date: 2023/10/28
 */
@Configuration
@Slf4j
public class SaTokenConfigure {


    /**
     * 创建Sa-Token的Reactor过滤器Bean
     * 
     * 该方法配置了一个SaReactorFilter实例，用于在Spring Cloud Gateway中
     * 实现基于Sa-Token的权限认证和访问控制。
     * 
     * 过滤器工作流程：
     * 1. 拦截所有请求（/**）
     * 2. 在setAuth方法中执行权限验证逻辑
     * 3. 根据不同的路由规则进行相应的权限检查
     * 4. 如果验证失败，会抛出相应的异常
     * 
     * @return SaReactorFilter 配置好的Sa-Token过滤器实例
     */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        SaReactorFilter filter = new SaReactorFilter();
        return filter
                // 设置拦截路径：拦截所有请求
                .addInclude("/**")
                .setAuth(obj -> {
                    // 进入 SaReactorFilter 的认证回调，打印以观测先后顺序
                    log.info("SaReactorFilter 认证回调, SaTokenConsts.ASSEMBLY_ORDER={}", SaTokenConsts.ASSEMBLY_ORDER);
                    log.info("SaReactorFilter 认证回调, path={}", SaHolder.getRequest().getRequestPath());
                    // 打印当前请求路径，用于调试和日志记录
                    log.info("前端访问path：{}", SaHolder.getRequest().getRequestPath());

                    // 认证服务路由权限控制
                    // 匹配所有以/auth/开头的请求路径
                    SaRouter.match("/auth/**")
                            .notMatch("/auth/user/getCaptcha")  // 排除验证码接口，允许未登录用户访问
                            .notMatch("/auth/user/doLogin")  // 排除登录接口，允许未登录用户访问
                            .check(r -> StpUtil.checkLogin()); // 其他认证接口需要登录验证

                    // 对象存储服务路由权限控制
                    // 所有OSS相关接口都需要登录后才能访问
                    SaRouter.match("/oss/**", r -> StpUtil.checkLogin());

                    // 题目管理特殊权限控制
                    // 添加题目接口需要特定的"subject:add"权限
                    SaRouter.match("/subject/subject/add", r -> StpUtil.checkPermission("subject:add"));

                    // 题目服务其他接口权限控制
                    // 除了添加题目外的其他题目相关接口只需要登录即可访问
                    SaRouter.match("/subject/**", r -> StpUtil.checkLogin());
                });
    }
}
